package org.youchan.aco.p2p;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;
import org.youchan.util.Message;

public class MessageReader {
	
	MessageReaderHander handler;
	
	public MessageReader() {
		handler = new MessageReaderHander();
	}
	
	public Message<SessionCommand> readMessage(String message) {
		try {
			InputStream is = new ByteArrayInputStream(message.getBytes("UTF-8"));
			return readMessage(is);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return handler.getMessage();
	}
	
	public Message<SessionCommand> readMessage(InputStream is) {
		try {
			createReader().parse(new InputSource(is));
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return handler.getMessage();
		
	}

	private XMLReader createReader() throws SAXException {
		handler.message = null;
		XMLReader reader = XMLReaderFactory.createXMLReader();
		reader.setContentHandler(handler);
		reader.setDTDHandler(handler);
		reader.setErrorHandler(handler);
		return reader;
	}
	class MessageReaderHander extends DefaultHandler {
		
		Message<SessionCommand> message;
		SessionCommand command;
		String currentValueName;
		StringBuffer currentValue;
		boolean currentValueArray;
		
		public Message<SessionCommand> getMessage() {
			return message;
		}
		
		public void startDocument() throws SAXException {
	    	message = null;
	    	command = null;
    		currentValueArray = false;
	    }
	    
	    public void endDocument() throws SAXException {
	    	message = new Message<SessionCommand>(command);
	    }
	    
	    public void startElement(java.lang.String uri,
	                       java.lang.String localName,
	                       java.lang.String qName,
	                       Attributes atts)
	                throws SAXException {
	    	if (localName.equals("message")) {
	    		if (command == null) {
	    	    	command = new SessionCommand(SessionCommand.Type.valueOf(atts.getValue("type").toUpperCase()));
	    		} else {
	    			throw new RuntimeException("<message> must be in top level.");
	    		}
	    	} else if (localName.equals("value")) {
	    		currentValueName = atts.getValue("name");
	    		currentValue = new StringBuffer();
	    	} else if (localName.equals("array")) {
	    		currentValueName = atts.getValue("name");
	    		currentValue = new StringBuffer();
	    		currentValueArray = true;
	    	}
	    }

	    public void endElement(java.lang.String uri,
	                       java.lang.String localName,
	                       java.lang.String qName)
	                throws SAXException {
	    	if (localName.equals("value")) {
	    		if (currentValueArray) {
	    			command.addValue(currentValueName, currentValue.toString());
	    		} else {
	    			command.setValue(currentValueName, currentValue.toString());
	    		}
	    	}
	    }

	    public void characters(char[] ch,
	                       int start,
	                       int length)
	                throws SAXException {
	    	currentValue.append(ch, start, length);
	    }

	    public void warning(SAXParseException e) {
	    }

	    public void error(SAXParseException e) {
	    }

	    public void fatalError(SAXParseException e) {
	    }
	}
}
